Basic

pack

print

Conversion

convert.a_to_ass

convert.ass_to_a

convert.rgb_to_ass

convert.ass_to_rgb

convert.text_to_pixels

convert.text_to_shape

convert.shape_to_pixels

convert.image_to_pixels

Input/Output

io.load_ass

io.progressbar

io.write_line

Math

math.bezier

math.degree

math.distance

math.ellipse

math.ortho

math.randomsteps

math.randomway

math.rotate

math.round

math.trim

Shapes

shape.bounding

shape.ellipse

shape.filter

shape.glance

shape.heart

shape.move

shape.rectangle

shape.ring

shape.split

shape.star

shape.tooutline

shape.triangle

Strings

string.ucharrange

string.uchars

string.ulen

Tables

table.append

table.copy

table.create

table.max

table.tostring

Utils

utils.distributor

utils.frames

utils.interpolate

utils.textextents


Legend:
RETURN_VALUES = FUNCTION(ARGUMENTS[, OPTIONAL])
FUNCTION DESCRIPTION
FUNCTION USAGE EXAMPLE
>>LOG OUTPUT
FUNCTION USAGE TIPS
PACKED_TUPLE = pack(...)
Opponent of unpack function. Puts given values into a table.
local vals = pack(5,4,3,2,1)
print( vals[4] )
>>2
Non information gets lost by functions with unknown number of return values.

print(...)
Converts values to strings and writes them to interface log.
print("Hello from GUI!", true, 123)
Useful for debugging. Print problematic values for error analysing.
ASS_ALPHA = convert.a_to_ass(ALPHA)
Converts given numeric alpha data into ASS alpha format.
print( convert.a_to_ass(0) )
>>&Hff&
Always needed for input of external alpha data to ASS format.

ALPHA = convert.ass_to_a(ASS_ALPHA)
Converts given ASS alpha string into numeric alpha data.
local a = convert.ass_to_a("&HFF&")
print("Alpha: " .. a)
>>Alpha: 0
Conversion allows to call mathematical methods on alpha channels.

ASS_RGB = convert.rgb_to_ass(R, G, B)
Converts given numeric RGB data into ASS color format.
print( convert.rgb_to_ass(255, 0, 0) )
>>&H0000ff&
Always needed for input of external color data to ASS format.

R, G, B = convert.ass_to_rgb(ASS_RGB)
Converts given ASS color string into numeric RGB data.
local r, g, b = convert.ass_to_rgb("&H00FF00&")
print("Red: " .. r .. "\nGreen: " .. g .. "\nBlue: " .. b)
>>Red: 0
>>Green: 255
>>Blue: 0
Conversion allows to call mathematical methods on colors.

PIXELS = convert.text_to_pixels(TEXT, STYLE[, OFF_X, OFF_Y])
Converts text with given style information and subpixel offset to a table with pixel data. Pixel informations are .x (horizontal position), .y (vertical position) and .a (alpha/transparency).
local line = table.copy(lines[1])
line.style = "p" --Style for pixels with f.e. \an7, \bord0, \shad0, ...
for pi, pixel in ipairs( convert.text_to_pixels(line.text, line.styleref, line.left % 1, line.top % 1) ) do
	local x, y = math.floor(line.left) + pixel.x, math.floor(line.top) + pixel.y
	local alpha = (pixel.a == 255 and "") or ("\\1a" .. convert.a_to_ass(pixel.a))
	line.text = string.format("{\\pos(%d,%d)%s\\p1}m 0 0 l 1 0 1 1 0 1", x, y, alpha)
	io.write_line(line)
end
Easy creation of text decaying or light effects.

SHAPE = convert.text_to_shape(TEXT, STYLE)
Converts text with given style information to an ASS shape command.
Important: Shape has 8-fold size!
local line = table.copy(lines[1])
line.text = string.format("{\\an7\\pos(%.3f,%.3f)\\p4}%s", line.left, line.top, convert.text_to_shape(line.text, line.styleref))
io.write_line(line)
Permits creation of text masks or deforming.

PIXELS = convert.shape_to_pixels(SHAPE[, DOWNSCALE])
Converts ASS shape command to a table with pixel data. Pixel informations are .x (horizontal position), .y (vertical position) and .a (alpha/transparency).
If downscale is true, given shape will be downscaled by factor 8 for rendering.
local line = table.copy(lines[1])
line.style = "p" --Style for pixels with f.e. \an7, \bord0, \shad0, ...
local rect = shape.rectangle(1,1)
for pi, pixel in ipairs( convert.shape_to_pixels("m 0 0 l 30 0 30 30 0 30") ) do
	local x, y = math.round(line.left + pixel.x), math.round(line.top + pixel.y)
	local alpha = (pixel.a == 255 and "") or ("\\1a" .. convert.a_to_ass(pixel.a))
	line.text = string.format("{\\pos(%d,%d)%s\\p1}%s", x, y, alpha, rect)
	io.write_line(line)
end
Even shapes can decay. Use downscale for text shapes!

PIXELS = convert.image_to_pixels(IMAGE_FILE)
Reads an image to a table with pixel data. Pixel informations are .x (horizontal position), .y (vertical position), .r (red), .g (green), .b (blue) and .a (alpha/transparency).
Supported image types: BMP, ICO, TGA, JPEG, PNG.
local line = table.copy(lines[1])
line.style = "p" --Style for pixels with f.e. \an7, \bord0, \shad0, ...
local img = convert.image_to_pixels("templates\\3_Function tests\\shield.png")
local rect = shape.rectangle(1,1)
for pi, pixel in ipairs(img) do
	if pixel.a > 0 then
		local x, y = 300 + pixel.x, 200 + pixel.y
		local color = convert.rgb_to_ass(pixel.r, pixel.g, pixel.b)
		local alpha = (pixel.a == 255 and "") or ("\\1a" .. convert.a_to_ass(pixel.a))
		line.text = string.format("{\\pos(%d, %d)\\1c%s%s\\p1}%s", x, y, color, alpha, rect)
		io.write_line(line)
	end
end
Small pictures with size 150x150 or less can move along karaoke text.
io.load_ass(ASS)
Defines global 'meta', 'styles' and 'lines' tables, filled with values which describe the content of given .ass file or ASS text itself.
io.load_ass( "templates\\3_Function tests\\in.ass" )
io.load_ass( [[
PlayResX: 704
PlayResY: 396
Style: Default,Arial,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1
Comment: 0,0:00:00.00,0:00:10.00,Default,,0000,0000,0000,,Test
]] )
Makes it possible to reload new .ass file contents to Lua and working with more than one .ass file.

io.progressbar(PERCENT)
Sets progressbar to given percent decimal number.
io.progressbar(0.5)
Update progressbar during the whole process to know how long you've to wait.

io.write_line(LINE)
Writes given dialog line to final output file in text format.
io.write_line(lines[1])
Most important function. Never modify it!
POINT = math.bezier(PERCENT, POINTS)
Calculates a point on bezier curve. Points is a table which containts tables with 2-3 numbers. Percent decimal number defines position on curve.
local point = math.bezier(0.3, {
	{0, 0, 0},
	{10, 20, -5},
	{20, -20, 5},
	{30, 0, 0}
})
print( point[1] .. " / " .. point[2] .. " / " .. point[3] )
>>9 / 5.04 / -1.26
Bezier curves allow non-linear movements and look mostly better than multiple linear moves.

DEG = math.degree(VEC1, VEC2)
Calculates the degree between two 3D vectors. Each vector is a table containing 3 numbers.
print(math.degree({1, 1, 0}, {1, 0, 0}))
>>-45
A lot of radial effects need calculations with vectors and the degree between them.

LENGTH = math.distance(WIDTH, HEIGHT[, DEPTH])
Calculates distance in 2D/3D room. Width, height and depth describing the vector in this room.
print( math.distance(8, 2) )
print( math.distance(8, 2, -3) )
>>8.2462112512353
>>8.7749643873921
Calculating distances between a constant point and pixels or vector points could be used for lighting or other gradient effects.

NEW_X, NEW_Y = math.ellipse(X, Y, WIDTH, HEIGHT, ANGLE)
Calculates a point on ellipse with given angle, center point x/y, width and height.
local x, y = math.ellipse(300, 200, 150, 100, 90)
print( x .. " / " .. y )
>>300 / 250
An ellipse can be a circle or an oval. Use it for round moves.

O_VEC = math.ortho(VEC1, VEC2)
Calculates the orthogonal vector of two 3D vectors. Each vector is a table containing 3 numbers.
print(table.tostring(
	math.ortho({1, 0, 0}, {0, 0, 1})
))
>>table: 02045598
>>	[1] = 0
>>	[2] = -1
>>	[3] = 0
In 2D, the orthogonal of a line vector and a depth vector can be the straight left or right line of the given line.

RANDOM_NUMBER = math.randomsteps(START, END, STRIDE)
Returns random number from start + x*stride until end.
for i=1, 3 do
	print( math.randomsteps(-2, 2, 0.5) )
end
>>-0.5
>>2
>>-1.5
Random numbers with specific distances allow more control by distribution.

DIRECTION = math.randomway()
Returns randomly -1 or 1 (50:50 chance).
for i=1, 3 do
	print( math.randomway() )
end
>>-1
>>1
>>-1
Useful for random directions.

ROTATED_POINT = math.rotate(POINT, AXIS, ANGLE)
Allows to rotate a point in 3D room.
local p = math.rotate({0, 5, 0}, "x", 180)
print( "X: " .. p[1] .. "\nY: " .. p[2] .. "\nZ: " .. p[3] )
>>X: 0
>>Y: -5
>>Z: 6.1230317691119e-016
Replacement if rotation tags are already in use. In combination with frame-per-frame processing, it allows movement in 3D room.

INTEGER = math.round(NUMBER)
Rounds number to nearest integer.
print( math.round(0.3) )
print( math.round(0.5) )
>>0
>>1
More precise for integer conversion than math.floor or math.ceil.

TRIMMED_NUMBER = math.trim(NUMBER, MIN, MAX)
Trims a number between a minimum and maximal number.
print( math.trim(0.5, 0, 1) )
print( math.trim(1.2, 0, 1) )
>>0.5
>>1
Easier than calculating a number, set it to a variable and check minimum and maximal case.
MIN_X, MIN_Y, MAX_X, MAX_Y = shape.bounding(SHAPE)
Returns bounding box of given shape.
print( string.format("Left-top: %d %d\nRight-bottom: %d %d", shape.bounding("m 10 5 l 25 5 25 42 10 42")) )
>>Left-top: 10 5
>>Right-bottom: 25 42
Gives a more precise information about text size by call with text shape than utils.textextents.

SHAPE = shape.ellipse(WIDTH, HEIGHT)
Returns a shape command of an ellipse with given width and height.
print( shape.ellipse(50, 80) )
>>m 0 40 b 0 40 0 0 25 0 b 25 0 50 0 50 40 b 50 40 50 80 25 80 b 25 80 0 80 0 40
Create rounded stribes or arcs in combination with blurring for light effects.

SHAPE = shape.filter(SHAPE, FILTER)
Sends every point of a shape through given filter function to change them.
print( shape.filter("m 0 0 l 20 0 20 10 0 10", function(x, y)
	return x+10, y+5
end))
>>m 10 5 l 30 5 30 15 10 15
Working with outline points can be used to deform the whole shape and make f.e. a wobble effect.

SHAPE = shape.glance(EDGES, INNER_DISTANCE, OUTER_DISTANCE)
Returns a shape command of a glance object with given number of outer edges. Edges have the distance to center of given outer distance. Control points for bezier curves between edges have the inner distance.
print( shape.glance(4, 0, 50) )
>>m 50 0 b 50 50 50 50 100 50 b 50 50 50 50 50 100 b 50 50 50 50 0 50 b 50 50 50 50 50 0
Glance is similar to Star, but with curves instead of inner edges between the outer edges.

SHAPE = shape.heart(SIZE, CENTER_Y_OFFSET)
Returns a shape command of a heart object with given size (width&height) and vertical offset of center point.
print( shape.heart(120, 80) )
>>m 60 120 b 108 88 120 72 120 56 b 120 32 88 0 60 120 b 32 0 0 32 0 56 b 0 72 12 88 60 120
An offset size*(2/3) results in a splitted heart.

SHAPE = shape.move(SHAPE, X, Y)
Moves shape coordinates in given direction.
print( shape.move("m 0 0 l 30 0 30 20 0 20", -5, 10) )
>>m -5 10 l 25 10 25 30 -5 30
Text shapes have to be shifted to screen position to use them as clip mask.

SHAPE = shape.rectangle(WIDTH, HEIGHT)
Returns a shape command of a rectangle with given width and height.
print( shape.rectangle(1, 1) )
>>m 0 0 l 1 0 1 1 0 1 0 0
A rectangle with width=1 and height=1 is a pixel.

SHAPE = shape.ring(OUTER_RADIUS, INNER_RADIUS)
Returns a shape command of a ring with given inner and outer radius.
print(shape.ring(100,80))
>>m 0 100 b 0 100 0 0 100 0 100 0 200 0 200 100 200 100 200 200 100 200 100 200 0 200 0 100 m 20 100 b 20 100 20 180 100 180 100 180 180 180 180 100 180 100 180 20 100 20 100 20 20 20 20 100
A ring with increasing inner radius, starting from 0, can look like an outfading point.

SHAPE = shape.split(SHAPE[, LINE_LENGTH])
Splits shape bezier curves into lines. Additional, it splits lines into shorter segments with maximum given length.
print( shape.split("m 0 0 l 300 0 b 300 200 0 200 0 0", 10) )
>>m 0 0 l 10 0 20 0 30 0 40 0 50 0 60 0 70 0 80 0 90 0 100 0 110 0 120 0 130 0 140 0 150 0 160 0 170 0 180 0 190 0 200 0 210 0 220 0 230 0 240 0 250 0 260 0 270 0 280 0 290 0 300 0 300 8 299 18 298 25 297 35 295 41 293 51 291 57 287 66 285 70 280 79 278 83 272 91 269 95 263 103 260 106 253 113 250 115 242 121 238 123 230 129 227 131 218 135 214 137 205 141 202 142 192 145 188 146 178 148 174 148 164 149 160 149 150 150 146 150 136 149 132 149 122 148 118 147 108 145 105 144 95 141 91 139 82 135 79 133 70 129 66 127 58 121 55 119 47 113 44 110 37 103 34 99 28 91 26 87 20 79 18 75 13 66 11 60 7 51 5 45 3 35 2 28 1 18 1 10 0 0
Should be done before using shape.filter to work with more outline points for smoother deforming.

SHAPE = shape.star(EDGES, INNER_DISTANCE, OUTER_DISTANCE)
Returns a shape command of a star object with given number of outer edges. Every second/inner edge has the inner distance to center, every outer edge the outer distance.
print( shape.star(5, 10, 30) )
>>m 28 0 l 33 22 56 21 37 33 45 54 28 40 11 54 19 33 0 21 23 22 28 0
Different numbers of edges and edge distances allow individual n-angles.

SHAPE = shape.tooutline(SHAPE, LINE_WIDTH)
Converts shape command for filling to a shape command for stroking.
print( shape.tooutline("m 0 0 l 100 0 100 50 0 50", 5) )
>>m 5 50 l 4 48 3 46 0 45 100 45 98 45 96 46 95 49 95 0 95 1 96 3 99 4 0 5 1 4 3 3 4 0 5 50 m -5 0 l -5 -2 -4 -4 -1 -5 100 -5 101 -5 103 -4 104 -1 105 50 104 51 103 53 100 54 0 55 -2 54 -4 53 -5 50 -5 0
Usable for border textures.

SHAPE = shape.triangle(SIDE_LENGTH)
Returns a shape command of an equilateral triangle with given side length.
print( shape.triangle(50) )
>>m 25 -7 l 0 36 50 36 25 -7
With \an5, the origin point is the center and z rotation works right.

RANGE = string.ucharrange(TEXT, INDEX)
Returns the utf8 length of the character in given text at position of given index.
local hiragana_A = "\227\129\130" 
print( string.ucharrange(hiragana_A, 1) )
>>3
Useful to detect unicode characters as strings of multiple Lua characters.

INDEX, CHAR = string.uchars(TEXT)
Iterator function for generic for-loop. Returns every pass an unicode character and his index of given text.
local ako = "\227\129\130\227\129\147" 
for ci, char in string.uchars(ako) do
	print(char)
end
>>ぁ
>>こ
The iterator alternative to the lines[i]chars table.

LENGTH = string.ulen(TEXT)
Returns the unicode length of given text.
local hiragana_A = "\227\129\130" 
print( string.len(hiragana_A) )
print( string.ulen(hiragana_A) )
>>3
>>1
The real length of a string which contains unicode characters.
table.append(TABLE1, TABLE2)
Appends fields of second table to first table. Numeric indices will be appended, literal indices overwritten.
local t1, t2 = {1, 2, a = "A"}, {3, 4, a = "B"}
table.append(t1, t2)
for i, v in pairs(t1) do
	print( i .. ": " .. v)
end
>>1: 1
>>2: 2
>>3: 3
>>4: 4
>>a: B
Fast fusion of two tables which had to be generated separately.

TABLECOPY = table.copy(TABLE)
Returns a deep copy of given table.
local t1 = {"hi"}
t2 = t1
t2[1] = "hello"
print( t1[1] )
t3 = table.copy(t1)
t3[1] = "bye"
print( t1[1] )
>>"hello"
>>"hello"
Creates a full copy and the original stays unchanged.

TABLE = table.create(ARRAY_SIZE, MAPPER_SIZE)
Creates a table with preallocated size.
local t = table.create(1000, 5)
for i=1, 1000 do
	t[i] = true
end
for i=97, 101 do
	t[string.char(i)] = true
end
Tables with preknown size should be created with this function for better performance.

SIZE = table.max(TABLE)
Returns the size of given table (numeric + literal indices).
local t = {a = 2, "hi"}
print( table.maxn(t) )
print( table.max(t) )
>>1
>>2
With this function you're knowing before how much passes a pairs call generates.

DESCRIPTION = table.tostring(TABLE)
Returns the given table as a text. Table contents are listed in a tree structure.
local t = {
	11,
	22,
	type = "info",
	{
		name = "Paul",
		true
	}
}
print( table.tostring(t) )
>>	[1] = 11
>>	[2] = 22
>>	[3] = table: 00B57680
>>		[1] = true
>>		["name"] = "Paul"
>>	["type"] = "info"
Useful supplement to print function for debugging.
DISTRIBUTOR_OBJECT = utils.distributor(TABLE)
Returns a distributor object which holds given table.
ENTRY = dist:get()
Returns the next value of distributor table in row.
local dist = utils.distributor({"&H0000FF&", "&H00FF00&", "&HFF0000&"})
for i=1, 4 do
	print( dist:get() )
end
>>&H0000FF&
>>&H00FF00&
>>&HFF0000&
>>&H0000FF&
Better multiple value flow than just using random picks.

FRAME_START, FRAME_END, INDEX, FRAMES = utils.frames(START_TIME, END_TIME, STRIDE)
Iterator function for generic for-loop. Arguments are the start time, end time and frame duration of a time zone. Returns every pass the current frame start time, end time, index and maximal number of frames.
for s, e, i, n in utils.frames(0, 100, 41.71) do
	print("Frame " .. i .. "/" .. n .. ": " .. s .. " - " .. e)
end
>>Frame 1/3: 0 - 41.71
>>Frame 2/3: 41.71 - 83.42
>>Frame 3/3: 83.42 - 100
Frame-per-frame operations without many calculation.

VALUE = utils.interpolate(PERCENT, VALUE1, VALUE2[, FILTER])
Interpolates given 2 values (ASS colors, ASS alpha channels or numbers) by percent value as decimal number. Filter can be "curve_up", "curve_down“ or a number (exponent) and influences the final percent value.
print( utils.interpolate(0.5, 10, 20) )
print( utils.interpolate(0.5, "&H0000FF&", "&H00FF00&", "curve_up") )
>>15
>>&H00ff00&
Easy calculation of color/alpha gradients.

WIDTH, HEIGHT, ASCENT, DESCENT, INTLEAD, EXTLEAD = utils.textextents(TEXT, STYLE)
Returns text size and font metric.
local text = "Test"
local style = {
	fontname = "Arial",
	fontsize = 60,
	bold = true,
	italic = true,
	underline = false,
	strikeout = false,
	encoding = 1,
	scale_x = 100,
	scale_y = 100,
	spacing = 1,
}
local w, h, a, d, i, e = utils.textextents(text, style)
print( "Width: " .. w .. "\nHeight: " .. h .. "\nAscent: " .. a .. "\nDescent: " .. d .. "\nInternal lead: " .. i .. "\nExternal lead: " .. e )
>>Width: 114.40625
>>Height: 60
>>Ascent: 48.625
>>Descent: 11.375
>>Internal lead: 6.296875
>>External lead: 1.75
Nearly always needed for operation with texts, but already used enough by preparing ASS values.

libjpeg license

(used in convert.image_to_pixels)
   The authors make NO WARRANTY or representation, either express or implied,
   with respect to this software, its quality, accuracy, merchantability, or
   fitness for a particular purpose.  This software is provided "AS IS", and you,
   its user, assume the entire risk as to its quality and accuracy.
   
   This software is copyright (C) 1991-1998, Thomas G. Lane.
   All Rights Reserved except as specified below.
   
   Permission is hereby granted to use, copy, modify, and distribute this
   software (or portions thereof) for any purpose, without fee, subject to these
   conditions:
   (1) If any part of the source code for this software is distributed, then this
   README file must be included, with this copyright and no-warranty notice
   unaltered; and any additions, deletions, or changes to the original files
   must be clearly indicated in accompanying documentation.
   (2) If only executable code is distributed, then the accompanying
   documentation must state that "this software is based in part on the work of
   the Independent JPEG Group".
   (3) Permission for use of this software is granted only if the user accepts
   full responsibility for any undesirable consequences; the authors accept
   NO LIABILITY for damages of any kind.
   
   These conditions apply to any software derived from or based on the IJG code,
   not just to the unmodified library.  If you use our work, you ought to
   acknowledge us.
   
   Permission is NOT granted for the use of any IJG author's name or company name
   in advertising or publicity relating to this software or products derived from
   it.  This software may be referred to only as "the Independent JPEG Group's
   software".
   
   We specifically permit and encourage the use of this software as the basis of
   commercial products, provided that all warranty or liability claims are
   assumed by the product vendor.